package snippet;

import java.io.File;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;

import be.ac.ulb.mlg.utils.Measure;
import be.ac.ulb.mlg.utils.Measurer;

public class TestMeasures {
	public static final double DIAGONAL_VALUE	= 0.0;
	
	public static void main(String[] args)throws Exception{
		
		final boolean autoparams = args.length != 3;
		String measureName = null;
		if(autoparams){
			System.out.println("No arguments, exiting");
			System.exit(0);
		}else{
			measureName = args[0];
		}
		
		final String INPUT	= System.getProperty("user.dir")+File.separator+"src"+File.separator+"snippet"+File.separator+args[1];
		final String OUTPUT	= args[2];
		
		
		System.out.println(INPUT);
		CSVLoader loader = new CSVLoader(false);
		loader.load(INPUT);
		
		final double[][] inputData = loader.data;
		System.out.println("Java input: "+inputData.length+" x "+inputData[0].length);

		@SuppressWarnings("unused")
		final int N = inputData.length, M = inputData[0].length;

		@SuppressWarnings("unchecked")
		final Class<Measure> measureClass	= (Class<Measure>) Class.forName("be.ac.ulb.mlg.utils.measure."+measureName);
		final Constructor<Measure>	cons	= getConstructor(measureClass);
		final Measure measure = cons.getParameterTypes().length<1?cons.newInstance():cons.newInstance(new Integer(M));
		
		Map<Measure,double[][]> result = null;
		
		Measurer measurer = new Measurer(false,0,null);
		measurer.useShuffling(false);
		measurer.usePreShuffle(false);
		measurer.setNumberOfThreads(1);
		result = measurer.measure(inputData, new Measure[]{measure});
		
		final double[][] outputData		= upper2full(result.values().iterator().next());
		System.out.println("Java output: "+outputData.length+" x "+outputData[0].length);

		CSVSaver saver = new CSVSaver(outputData);
		saver.save(OUTPUT == null?System.out:new PrintStream(OUTPUT));
	}
	static void println(double[] ds) {
		for(double d:ds) System.out.print(d+" ");
		System.out.println();
	}
	static Constructor<Measure> getConstructor(Class<Measure> measureClass){
		@SuppressWarnings("unchecked")
		Constructor<Measure>[] constructors = (Constructor<Measure>[]) measureClass.getDeclaredConstructors();
		if(constructors.length < 1) return null;
		Arrays.sort(constructors,new Comparator<Constructor<Measure>>(){
			@Override
			public int compare(Constructor<Measure> a,Constructor<Measure> b) {
				int res = new Integer(a.getParameterTypes().length).compareTo(new Integer(b.getParameterTypes().length));
				if(res != 0) return res;
				return map(a.getParameterTypes()).compareTo(map(b.getParameterTypes()));
			}
			private boolean checkType(String className,Class<?> klass){
				return checkType(className,klass,klass.getSimpleName().toLowerCase());
			}
			private boolean checkType(String className,Class<?> klass,String shortName){
				return className.equals(klass.getName()) || className.equals(shortName);
			}
			private String map(Class<?>[] a){
				StringBuffer buff = new StringBuffer(a.length);
				for(Class<?> c:a){
					String name = c.getName();
					if(checkType(name,Boolean.class)){
						buff.append('a');
					}else if(checkType(name,Byte.class)){
						buff.append('b');
					}else if(checkType(name,Character.class,"char")){
						buff.append('c');		
					}else if(checkType(name,Integer.class,"int")){
						buff.append('d');
					}else if(checkType(name,Float.class)){
						buff.append('e');
					}else if(checkType(name,Long.class)){
						buff.append('f');
					}else if(checkType(name,Double.class)){
						buff.append('g');
					}else{
						buff.append('z');
					}
				}
				return buff.toString();
			}
		});
		return constructors[0];
	}
	static void info(String string) {
		System.out.println(string);
	}
	static double[][] upper2full(double[][] upperMatrix){
		double[][] result = new double[upperMatrix.length+1][upperMatrix.length+1];
		int i,j,k;
		for(i=0;i<upperMatrix.length;i++){
			for(j=i+1,k=0;j<result.length;j++,k++){
				result[j][i] = result[i][j] = upperMatrix[i][k];
			}
		}
		return result;
	}
	static double[][] reverse(double[][] input){
		final int N = input[0].length;
		final int M = input.length;
		final double[][] output = new double[N][M];
		for(int newRow=0;newRow<N;newRow++){
			for(int newColumn=0;newColumn<M;newColumn++)
				output[newRow][newColumn] = input[newColumn][newRow];
		}
		return output;
	}
}
